package com._21cn.cms.template.utils;

import com._21cn.cms.article.entity.Article;
import com._21cn.cms.article.entity.Special;
import com._21cn.cms.article.service.SpecialService;
import com._21cn.cms.article.utils.ArticleHelper;
import com._21cn.cms.common.Constants;
import com._21cn.cms.site.ConfigKeys;
import com._21cn.cms.site.entity.*;
import com._21cn.cms.site.service.*;
import com._21cn.cms.template.entity.Template;
import com._21cn.cms.template.entity.vo.Page;
import com._21cn.cms.template.service.TemplateService;
import com._21cn.cms.template.utils.label.ArticleListLabel;
import com._21cn.cms.template.utils.label.ArticleListLabel.ArticleListQuery;
import com._21cn.cms.template.utils.label.RegionObjLabel;
import com._21cn.cms.template.utils.label.ToolsLabel;
import com._21cn.framework.utils.StringUtil;
import org.apache.commons.io.FileUtils;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by Thinkpad on 2017/4/6.
 */
@Component
public class TemplateHelper {
    private static final String ARTICLE_PAGE_PRE = "上一页";
    private static final String ARTICLE_PAGE_NEXT = "下一页";
    private static final String ARTICLE_PAGE_REMAIN = "显示全文";
    private SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MMdd/HH/");

    @Autowired
    private ArticleListLabel articleListLabel;

    @Autowired
    private ToolsLabel toolsLabel;

    @Autowired
    private RegionObjLabel regionObjLabel;

    @Autowired
    private ColumnService columnService;

    @Autowired
    private ColumnCopyService columnCopyService;

    @Autowired
    private ChannelService channelService;

    @Autowired
    private ConfigService configService;

    @Autowired
    private TemplateService templateService;

    @Autowired
    private ArticleHelper articleHelper;

    @Autowired
    private RegionService regionService;

    @Autowired
    private SpecialService specialService;


    //生成区块页
    public void generateRegionPage( Integer id ){
        Region region = regionService.getById(id);
        Set<Integer> templateIdSet = StringUtil.str2IntSet(region.getTemplateIdList());
        for(Integer templateId : templateIdSet){
            if( templateId>0 && region.getType().equals(com._21cn.cms.article.Constants.REGION_TYPE_INCLUDE) ){
                Template template = templateService.getById(templateId);
                Page page = new Page();
                page.setTemplate(template);
                page.setRegion(region);
                page.setPageType(Constants.TEMPLATE_TYPE_REGION_INCLUDE);
                String regionPath = region.getPath().replace("{templateId}", templateId+"");
                page.setStaticFilePath(regionPath);
                generatePage(page);
            }
        }
    }
    //生成栏目列表
    public void generateColumnPage( Integer id ){
        Column column = columnService.getById(id);
        if( column.getListTemplateId()>0 ){
            Template template = templateService.getById(column.getListTemplateId());
            Column srcColumn = this.columnCopyService.getSrcColumn(id);
            Page page = new Page();
            page.setTemplate(template);
            page.setColumn(column);
            page.setSrcColumn(srcColumn);
            page.setPageType(Constants.TEMPLATE_TYPE_COLUMN_LIST);
            page.setStaticFilePath(column.getPath()+"/list{1}.shtml");
            generatePage(page);
        }
    }
    public void generateSpecialPage(Integer id) {
        Special special = specialService.getById(id);
        if (!StringUtil.isEmpty(special.getTemplateContent())) {
            Integer channelId = special.getChannelId();
            String code = special.getCode();
            Channel channel = this.channelService.getById(channelId);
            Template template = new Template();
            template.setTemplateType(Constants.TEMPLATE_TYPE_SPECIAL);
            template.setId(Integer.valueOf(9999));
            template.setContent(special.getTemplateContent());
            Page page = new Page();
            page.setTemplate(template);
            page.setChannel(channel);
            page.setStaticFilePath(special.getPath());
            generatePage(page);
        }
    }
    //生成频道列表
    public void generateChannelPage( Integer id ){
        Channel channel = channelService.getById(id);
        if( channel.getIndexTemplateId()>0 ){
            Template template = templateService.getById(channel.getIndexTemplateId());
            Page page = new Page();
            page.setTemplate(template);
            page.setChannel(channel);
            page.setPageType(Constants.TEMPLATE_TYPE_CHANNEL_INDEX);
            page.setStaticFilePath(channel.getPath()+"/index.shtml");
            generatePage(page);
        }
    }

    public List<String> generatePage(Page page){
        return generatePage(page, false);
    }

    public List<String> generatePage(Page page, boolean preview){
        List<String> result = new ArrayList<String>();
        try{
            if( page==null || page.getTemplate().getId()<=0 ){
                return result;
            }
            String outPath = page.getStaticFilePath();
            switch (page.getPageType()) {
                case Constants.TEMPLATE_TYPE_CHANNEL_INDEX :         //频道首页
                    if( page.getChannel()!=null && page.getChannel().getId()>0 ){
                        result = generateIndex(page, outPath,  preview);
                    }
                    break;
                case Constants.TEMPLATE_TYPE_COLUMN_LIST :          //栏目列表页
                    if( page.getColumn()!=null && page.getColumn().getId()>0 ){
                        Column column = page.getColumn();
                        Integer columnId = column.getId();
                        result = generateList(page, outPath, articleListLabel.column(columnId+""), preview);
                    }
                    break;
                case Constants.TEMPLATE_TYPE_ARTICLE_CONTENT :      //文章内容页
                    if( page.getArticle()!=null && page.getArticle().getId()>0 ){
                        result = generateArticle( page, outPath , preview);
                    }
                    break;
                case Constants.TEMPLATE_TYPE_REGION_INCLUDE :      //区块嵌套页
                    if( page.getRegion()!=null && page.getRegion().getId()>0 ){
                        result = generateRegion( page, outPath , preview);
                    }
                    break;
                case Constants.TEMPLATE_TYPE_SPECIAL :             //专题
                    result = generateSpecial(page, outPath, preview);
                    break;

            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }

    public List<String> generateIndex(Page page, String outFilePath, boolean preview ){
        List<String> result = new ArrayList<String>();
        try {
            Template template = page.getTemplate();
            if (template == null || template.getId() <= 0) {
                return result;
            }
            Map<String, Object> maps = new HashMap<String, Object>();
            maps.put("articleListLabel", articleListLabel);
            maps.put("toolsLabel", toolsLabel);
            maps.put("regionObjLabel", regionObjLabel);
            maps.put("page", page);
            String templateContent = template.getContent();
            String pageContent = evaluateTemplate(templateContent, maps);
            if(!StringUtil.isEmpty(outFilePath) && !preview){
                generateFile(outFilePath, pageContent, "UTF-8");
            }
            result.add(pageContent);
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }

    public List<String> generateRegion(Page page, String outFilePath, boolean preview ){
        return generateIndex(page, outFilePath, preview);
    }

    public List<String> generateSpecial(Page page, String outFilePath, boolean preview) {
        return generateIndex(page, outFilePath, preview);
    }

    /**
     * 获取或生成解析后的文章
     * @param page 页面里栏目不一定是主栏目
     * @param outFilePath 文章物理地址
     * @return 解析后的文章（各分页内容的集合）
     */
    public List<String> generateArticle( Page page, String outFilePath, boolean preview ){
        List<String> result = new ArrayList<String>();
        try {
            Template template = page.getTemplate();
            if(template == null||template.getId()<=0){
                return result;
            }
            Article article = page.getArticle();
            if( article!=null && article.getId()>0 ){
                if( page.getColumn()==null || page.getColumn().getId()<=0 ){
                    if( article.getColumn()== null||article.getColumn().getId()<=0 ){
                        int columnId = article.getColumnId();
                        Column column = columnService.getById(columnId);
                        if( column!=null ){
                            page.setColumn(column);
                            page.setChannel(column.getChannel());
                        }
                    }else {
                        page.setColumn(article.getColumn());
                        page.setChannel(article.getChannel());
                    }
                }
                Map<String, Object> maps = new HashMap<String, Object>();
                maps.put("articleListLabel", articleListLabel);
                maps.put("regionObjLabel", regionObjLabel);
                maps.put("toolsLabel", toolsLabel);
                maps.put("article", article);
                maps.put("page", page);
                String templateContent = template.getContent();
                List<String> pageContentList = article.getPageContentList();
                int totalPage = pageContentList.size();

                for(int i=0; i<totalPage; i++){
                    article.setContent(pageContentList.get(i));

                    String[] pageString = getStaticPageNav(article.getId(), i, totalPage);
                    if(pageString.length > 0){
                        page.setPrevPageNav( pageString[0] );
                        page.setNextPageNav( pageString[1] );
                        page.setCountPageNav( pageString[3] );
                        page.setPagerNav( pageString[0]+pageString[2]+pageString[1]+pageString[4] );
                    }
                    String[] pageNavList = getPageNav(article.getId()+"", i + 1, totalPage );
                    if(pageNavList.length > 0){
                        page.setShortPagerNav( pageNavList[0]+pageNavList[2]+pageNavList[1] );
                    }

                    String pageContent = evaluateTemplate(templateContent, maps);

                    if(!StringUtil.isEmpty(outFilePath) && !preview){
                        if (i == 0) {   //第一页再生成一个没有数字的文件名
                            generateFile(outFilePath, pageContent, "UTF-8");
                        }else {
                            generateFile(outFilePath.replace(".shtml", "_" + i + ".shtml"), pageContent, "UTF-8");
                        }
                    }
                    result.add( pageContent );
                }

                if( !pageContentList.isEmpty() && totalPage > 1 ){//生成全部页面
                    StringBuilder buf = new StringBuilder();
                    for(int i = 0;i<pageContentList.size();i++){
                        String s  = pageContentList.get(i);
                        String pageAnchor = "<a name='p"+(i+1)+"'></a>";
                        buf.append(s).append(pageAnchor);
                    }
                    article.setContent(buf.toString());

                    page.setPagerNav("");
                    page.setShortPagerNav("");
                    String resultContent = evaluateTemplate( templateContent, maps);
                    if(!StringUtil.isEmpty(outFilePath)){
                        generateFile(outFilePath.replace(".shtml", "_all.shtml"), resultContent,"UTF-8");
                    }
                    result.add(resultContent);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public List<String> generateArticle( Article article , String clientCode){
        articleHelper.regulatePager(article);
        String configKey = ConfigKeys.KEY_CONFIG_ARTICLE_TEMPLATE_PC;
        if(clientCode.equals("m")){
            configKey = ConfigKeys.KEY_CONFIG_ARTICLE_TEMPLATE_WAP;
        }else if(clientCode.equals("c")){
            configKey = ConfigKeys.KEY_CONFIG_ARTICLE_TEMPLATE_APP;
        }
        Template template = getArticleTemplateId(article, configKey);
        Page page = new Page();
        page.setTemplate(template);
        page.setArticle(article);
        String staticFilePath = getArticleStaticFilePath(article, clientCode);
        page.setStaticFilePath(staticFilePath);
        List<String> list = generatePage(page, false);
        return list;
    }

    /**
     * 生成列表页
     * @param page
     * @param targetPath
     * @param articleListQuery
     * @return
     */
    public List<String> generateList(Page page , String targetPath, ArticleListQuery articleListQuery, boolean preview){
        List<String> result = new ArrayList<String>();
        try {
            if( page==null || page.getTemplate().getId()<=0 ){
                return result;
            }
            Template template = page.getTemplate();
            Map<String, Object> maps = new HashMap<String, Object>();
            articleListLabel.setArticleListQuery(articleListQuery);
            maps.put("articleListLabel", articleListLabel);
            maps.put("regionObjLabel", regionObjLabel);
            maps.put("toolsLabel", toolsLabel);
            maps.put("page", page);
            String templateContent = template.getContent();
            int count = articleListQuery.count();
            if( count>0 ){
                int totalPage = Constants.DEFAULT_TOTAL_PAGE;
                if (articleListQuery.getPageTurn().getPageCount() > 0 && articleListQuery.getPageTurn().getPageCount() < totalPage) {
                    totalPage = articleListQuery.getPageTurn().getPageCount();
                }
                for (int i = 0; i < totalPage; i++) {
                    String[] pageTurnString = getPageTurnString(i + 1, totalPage);
                    if (pageTurnString.length > 1) {
                        page.setPrevPageNav(pageTurnString[0]);
                        page.setNextPageNav(pageTurnString[1]);
                        page.setCountPageNav(pageTurnString[3]);
                        page.setPagerNav(pageTurnString[0] + pageTurnString[2] + pageTurnString[1]);
                    }
                    String[] pageNavList = getPageNav("list", i + 1, totalPage);
                    if (pageNavList.length > 0) {
                        page.setShortPagerNav(pageNavList[0] + pageNavList[2] + pageNavList[1]);
                    }
                    articleListQuery.setPageNo(i + 1);
                    String outFilePath = targetPath.replace("{1}", String.valueOf(i + 1));
                    String pageContent = evaluateTemplate(templateContent, maps);
                    if( !preview ){
                        if (i == 0) {   //第一页再生成一个没有数字的文件名
                            generateFile(targetPath.replace("{1}", "1"), pageContent, "UTF-8");
                        }else {
                            generateFile(outFilePath, pageContent, "UTF-8");
                        }
                    }
                    result.add( pageContent );
                }
            }else{
                String pageContent = evaluateTemplate(templateContent, maps);
                if( !preview ){
                    generateFile(targetPath.replace("{1}", ""), pageContent, "UTF-8");
                }
                result.add( pageContent );
            }

        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 解析模版内容
     * @param templateContent 模版内容
     * @param maps 模版变量
     * @return 返回解析后的内容
     */
    public static String evaluateTemplate(String templateContent, Map<String,Object>... maps){
        VelocityContext context = new VelocityContext();
        for(Map<String,Object> map: maps){
            for(Map.Entry<String, Object> entry : map.entrySet()){
                context.put(entry.getKey(), entry.getValue());
            }
        }
        StringWriter writer = new StringWriter();
        try{
            Velocity.evaluate(context, writer, "template", templateContent);
        }catch(Exception e){
            e.printStackTrace();
        }
        return writer.toString();
    }

    public void generateFile( String outFilePath, String content, String charset ){
        try {
            File outFile = new File(outFilePath);
            FileUtils.write(outFile, content, charset, false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String[] getPageTurnString(int currentPage, int totalPage) {
        String prevListPage = "";
        String nextListPage = "";
        if (currentPage > 1) {
            prevListPage = "<a href='list" + (currentPage - 1) + ".shtml'>" + ARTICLE_PAGE_PRE + "</a>";
        }
        if (currentPage < totalPage) {
            nextListPage = "<a href='list" + (currentPage + 1) + ".shtml'>" + ARTICLE_PAGE_NEXT + "</a>";
        }

        int listStep = 5;//显示分页页数
        int listBegin = (currentPage - (int) Math.ceil((double) listStep / 2));
        if (listBegin < 1) {
            listBegin = 1;
        }
        int listEnd = currentPage + listStep / 2;
        if (listEnd >= totalPage) {
            listEnd = totalPage;
        }

        StringBuffer middleListPage = new StringBuffer();
        for(int i = listBegin; i <= listEnd; i++){
            if(currentPage == i){
                middleListPage.append(i+"&nbsp;");
            }else{
                middleListPage.append("<a href='list"+ i + ".shtml' >"+i+"</a>&nbsp;");
            }
        }

        String countPageNav = currentPage + "/" + totalPage;
        return new String[]{prevListPage, nextListPage, middleListPage.toString(), countPageNav};
    }

    /**
     * 组装文章的分页（生成）
     * @param articleId 文章ID
     * @param currentPage 当前页数
     * @param totalPage 总页数
     * @return
     */
    private static String[] getStaticPageNav( int articleId, int currentPage, int totalPage ) {
        if (totalPage > 1) {
            String spn_pre = ""; // '上一页'的文字
            StringBuilder spn_mid = new StringBuilder(); // 中间各页的
            String spn_post = ""; // '下一页'的文字
            String currentLink = ""; // 当前页的链接
            String prePageLink = ""; // '上一页'的链接
            String postPageLink = ""; // '下一页'的链接
            String postfix = ""; // 每页文件名的后缀
            String suffix = ".shtml";
            // 导航前面部分 '上一页'
            if (currentPage != 0) {
                prePageLink = articleId + getSubPagePostfix(currentPage - 1) + suffix;
                spn_pre = "<a target=\"_self\" href=\"" + prePageLink + "\">" + ARTICLE_PAGE_PRE + "</a>";
            }else{
                spn_pre = "<span class='pre_pager_btn'></span>";
            }
            for (int j = 0; j < totalPage; j++) {
                if (j > 0) { // >0即为分页
                    postfix = getSubPagePostfix(j); // 取得分页文件名的后缀部分
                }
                currentLink = articleId + postfix + suffix;

                // 导航中间部分
                if (j == currentPage) {
                    spn_mid.append("<span class='mid_pager_btn'>").append(j + 1).append("</span>");
                } else {
                    spn_mid.append("<a target=\"_self\" href=\"").append(currentLink).append("\">").append(j + 1).append("</a>");
                }
                if (totalPage > 13) {
                    if (j != 0 && (j + 1) % 12 == 0) {
                        //spn_mid.append("<br>");
                    }
                }
            }

            // 导航后面部分 '下一页'
            if (currentPage != (totalPage - 1)) {
                postPageLink = articleId + getSubPagePostfix(currentPage + 1) + suffix;
                spn_post = "<a target=\"_self\" href=\"" + postPageLink + "\">" + ARTICLE_PAGE_NEXT + "</a>";
            }else{
                spn_post = "<span class='next_pager_btn'></span>";
            }
            String countPageNav = "<span class='count_pager_btn'>"+ (currentPage + 1) + "/" + totalPage+"</span>";
            // 导航后面部分 '显示全文'
            String spn_remain = "";
            String remainPageLink = articleId + "_all" + suffix;
            if (currentPage != totalPage) {
                spn_remain = "<a target=\"_self\" href=\"" + remainPageLink + ((currentPage != totalPage - 1) ? "#p" + (currentPage + 1) : "") + "\">" + ARTICLE_PAGE_REMAIN + "</a>";
            }
            return new String[]{spn_pre, spn_post, spn_mid.toString(), countPageNav, spn_remain};
        } else {
            return new String[]{};
        }
    }

    private static String[] getPageNav( String fileName, int currentPage, int totalPage ) {
        if (totalPage > 1) {
            String prev = ""; // 上一页
            StringBuffer pageMid = new StringBuffer(); // 中间各页的
            String next = ""; // '下一页'
            String currentLink = ""; // 当前页的链接
            String prevPageLink = ""; // '上一页'的链接
            String nextPageLink = ""; // '下一页'的链接
            String postfix = ""; // 每页文件名的后缀
            String suffix = ".shtml";

            // 导航前面部分 '上一页'
            if (currentPage != 1) {
                prevPageLink = fileName + getNewPagePostfix(fileName, fileName.equals("list")?currentPage-1:currentPage-2) + suffix;
                prev = "<a class='prev' target=\"_self\" href=\"" + prevPageLink + "\">上页</a>";
            }else{
                prev = "<span class='prev'>上页</span>";
            }

            if(totalPage>5 && (currentPage-3) >= 1){//是否显示第一页
                pageMid.append("<a class='first' target='_self' href='" + fileName + (fileName.equals("list")?"1":"") + suffix + "'>1</a>");
                if((currentPage-3) != 1){
                    pageMid.append("<span class='dot'>...</span>");
                }
            }

            // 导航中间部分
            int pageNoEnd = (currentPage < 4 ? 5 : currentPage + 2);
            int end = (pageNoEnd > totalPage ? totalPage : pageNoEnd);
            int pageNoBegin = (currentPage - (4 - (end - currentPage)));
            int begin = (pageNoBegin < 1 ? 1 : pageNoBegin);

            for (int j = begin; j <= end; j++) {
                postfix = getNewPagePostfix(fileName, (fileName.equals("list")?j:j-1)); // 取得分页文件名的后缀部分
                currentLink = fileName + postfix + suffix;
                if (j == currentPage) {
                    pageMid.append("<span class='current'>" + j + "</span>");
                } else {
                    pageMid.append("<a target=\"_self\" href=\"" + currentLink + "\">" + j + "</a>");
                }
            }

            if(totalPage>5 && (currentPage+3) <= totalPage){//是否显示最后一页
                if(currentPage+3 != totalPage){
                    pageMid.append("<span class='dot'>...</span>");
                }
                pageMid.append("<a target='_self' class='last' href='"+ fileName + getNewPagePostfix(fileName, fileName.equals("list")?totalPage:totalPage-1) + suffix+"'>"+totalPage+"</a>");
            }

            // 导航后面部分 '下一页'
            if (currentPage != totalPage) {
                nextPageLink = fileName + getNewPagePostfix(fileName, fileName.equals("list")?currentPage+1:currentPage) + suffix;
                next = "<a class='next' target=\"_self\" href=\"" + nextPageLink + "\">下页</a>";
            }else{
                next = "<span class='next'>下页</span>";
            }

            String countPageNav = "<span class='count'>"+ currentPage + "/" + totalPage+"</span>";
            return new String[]{prev, next, pageMid.toString(), countPageNav};
        } else {
            return new String[]{};
        }
    }

    private static String getNewPagePostfix(String fileName, int page){
        if(!StringUtil.isEmpty(fileName) && page>0){
            if(fileName.equals("list")){
                return page+"";
            }else{
                return "_"+page;
            }
        }
        return "";
    }

    private static String getSubPagePostfix(int k) {
        if (k == 0) { // 第0页是没有下标的
            return "";
        } else { // 除第0页后均加下标: "_" + 页码
            return "_" + k;
        }
    }

    /**
     * 获取文章模板id
     * @param article
     * @return
     */
    public Template getArticleTemplateId( Article article , String key){
        Template template = null;
        Integer templateId = 0;
        if(article!=null && article.getId()>0){
            Integer columnId = article.getColumnId();
            Integer channelId = article.getChannelId();
            Integer siteId = article.getSiteId();
            Config config = configService.getConfig(siteId, channelId, columnId, key);
            if(config == null){
                config = configService.getConfig(siteId, channelId, 0, key);
                if(config == null){
                    config = configService.getConfig(siteId, 0, 0, key);
                }
            }
            if(config != null){
                templateId = Integer.valueOf(config.getValue());
                template = templateService.getById(templateId);
            }
        }
        return template;
    }

    /**
     * 生成静态页面的地址
     *
     * @param article
     * @return
     */
    public String getArticleStaticFilePath(Article article, String clientCode) {
        String articleStaticFolder = getArticleStaticFolder(article, clientCode);
        return new StringBuilder(articleStaticFolder).append(article.getId()).append(".shtml").toString();
    }

    public String getArticleStaticFolder(Article article, String clientCode){
        Column column = article.getColumn();
        if( column==null ){
            column = columnService.getById(article.getColumnId());
        }
        return new StringBuilder(column.getPath()).append("/").append(clientCode)
                .append(sdf.format(article.getPublishTime())).toString();
    }

    public String getArticleStaticFolder(String path, String articleUrl) {
        String foldPath = new StringBuilder().append(path).append(articleUrl.replace("http://", "/")).toString();
        foldPath = foldPath.replaceAll("(\\d+).shtml", "");
        return foldPath;
    }

    public String getSiteStaticPath(Site site) {
        String siteCode = site.getCode();
        String siteStaticPath = new StringBuilder().append("/data/").append(siteCode).append("/page").toString();
        return siteStaticPath;
    }
}
